#include "segmentsmerger.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>

SegmentsMerger::SegmentsMerger(QObject* parent) : QObject(parent)
{
    m_process = new QProcess(this);
    connect(m_process, &QProcess::errorOccurred, this, &SegmentsMerger::handleProcessError);
    connect(m_process, &QProcess::finished, this, &SegmentsMerger::handleProcessExit);
}

SegmentsMerger::~SegmentsMerger()
{
    if (m_process) {
        disconnect(m_process, nullptr, this, nullptr);
        if (m_process->state() == QProcess::Running || m_process->state() == QProcess::Starting) {
            // First try to terminate gracefully
            m_process->terminate();
            if (!m_process->waitForFinished(10000)) { // Wait 5 seconds for graceful termination
                qWarning() << "Process did not terminate gracefully, forcing kill";
                m_process->kill();
                if (!m_process->waitForFinished(10000)) { // Wait another 5 seconds after kill
                    qWarning() << "Failed to kill process after 10 seconds";
                }
            }
        }
        delete m_process;
    }
}

bool SegmentsMerger::mergeSegments(const QString& segmentsDir, const QString& outputPath,
                                   const QStringList& segmentFiles)
{
    if (segmentFiles.isEmpty()) {
        emit errorOccurred(NO_SEGMENTS_ERROR, tr("No segments to merge"));
        return false;
    }

    m_outputPath = outputPath;

    // Validate segments before merging
    if (!validateSegments(segmentsDir, segmentFiles)) {
        emit errorOccurred(INVALID_SEGMENTS_ERROR, tr("Invalid segments found"));
        return false;
    }

    // Create file list for merging
    const QString listFilePath = QDir(segmentsDir).absoluteFilePath("filelist.txt");
    if (!createFileList(segmentsDir, listFilePath, segmentFiles)) {
        emit errorOccurred(CREATE_MERGE_FILELIST_ERROR, tr("Failed to create file list"));
        return false;
    }

    // Prepare FFmpeg command
    QStringList args = { "-y", "-f",         "concat", "-safe", "0",
                         "-i", listFilePath, "-c",     "copy",  outputPath };

    // Start FFmpeg process
    m_process->start("ffmpeg", args);
    if (!m_process->waitForStarted(10000)) {
        emit errorOccurred(START_MERGE_PROCESS_ERROR, tr("Failed to start merge process"));
        return false;
    }

    return true;
}

bool SegmentsMerger::createFileList(const QString& segmentsDir, const QString& listFilePath,
                                    const QStringList& segmentFiles)
{
    QFile listFile(listFilePath);
    if (!listFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        qWarning() << "Failed to create file list:" << listFile.errorString();
        return false;
    }

    for (const auto& file : segmentFiles) {
        const QFileInfo fi(QDir(segmentsDir).absoluteFilePath(file));
        if (fi.size() >= 1024) { // Only include files larger than 1KB
            listFile.write(QString("file '%1'\n").arg(file).toUtf8());
        }
    }

    listFile.close();
    return true;
}

bool SegmentsMerger::validateSegments(const QString& segmentsDir, const QStringList& segmentFiles)
{
    for (const auto& file : segmentFiles) {
        QFileInfo fi(QDir(segmentsDir).absoluteFilePath(file));
        if (!fi.exists() || fi.size() < 1024) {
            qWarning() << "Invalid segment:" << file;
            return false;
        }
    }
    return true;
}

void SegmentsMerger::cleanup(const QString& segmentsDir)
{
    QDir dir(segmentsDir);
    if (dir.exists()) {
        dir.removeRecursively();
    }
}

void SegmentsMerger::handleProcessError(QProcess::ProcessError error)
{
    QString errorMsg;
    switch (error) {
    case QProcess::FailedToStart:
        errorMsg = tr("FFmpeg failed to start");
        break;
    case QProcess::Crashed:
        errorMsg = tr("FFmpeg process crashed");
        break;
    default:
        errorMsg = tr("FFmpeg process error: %1").arg(m_process->errorString());
    }
    emit errorOccurred(MERGE_PROCESS_ERROR, errorMsg);
}

void SegmentsMerger::handleProcessExit(int exitCode, QProcess::ExitStatus exitStatus)
{
    if (exitStatus == QProcess::NormalExit && exitCode == 0) {
        // Verify the output file
        QFileInfo outputFile(m_outputPath);
        if (outputFile.exists() && outputFile.size() > 1024) {
            emit finished(m_outputPath);
        } else {
            emit errorOccurred(INVALID_OUTPUT_FILE_ERROR, tr("Invalid output file"));
        }
    } else {
        emit errorOccurred(MERGE_PROCESS_EXIT_ERROR,
                           tr("Merge process failed with exit code: %1").arg(exitCode));
    }
}
